home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer)…68k, x86, SPARC, PA-RISC] / NeXTSTEP 3.3 Dev Intel.iso / NextDeveloper / Examples / AppKit / Backspace / Thinker.m < prev    next >
Encoding:
Text File  |  1994-06-27  |  19.0 KB  |  896 lines

  1. //  Thinker.m
  2. //
  3. //  This class is the brains behind the BackSpace app; it is the Application
  4. //  object's delegate, and it watches the system to determine when to
  5. //  initiate the screen saver mode.
  6. //
  7. //  You may freely copy, distribute, and reuse the code in this example.
  8. //  NeXT disclaims any warranty of any kind, expressed or  implied, as to its
  9. //  fitness for any particular use.
  10.  
  11.  
  12. #import "Thinker.h"
  13. #import "BackWindow.h"
  14. #import "BackView.h"
  15. #import "SpaceView.h"
  16. #import "MySlider.h"
  17. #import "Password.h"
  18. #import "psfuncts.h"
  19.  
  20. #import <appkit/appkit.h>
  21. #import <objc/NXBundle.h>
  22.  
  23. // convert vertical blank time to milliseconds
  24. #define SEC2MS(x) ((x * 1000) + 20)
  25.  
  26. //#define SHOWITERATIONSPERSEC
  27.  
  28. #ifdef SHOWITERATIONSPERSEC
  29. unsigned iterations;
  30. BStimeval then, now, targetTime;
  31. #endif
  32.  
  33. static id _BSThinker;
  34.  
  35. id BSThinker()
  36. {    return _BSThinker;
  37. }
  38.  
  39.  
  40. @implementation Thinker
  41.  
  42. - appDidInit:sender
  43. {
  44.     const char *autoLaunch;
  45.     globalTier = BACKGROUNDTIER;
  46.     openAnother = YES;
  47.     _BSThinker = self;
  48.  
  49.     backZone = NXCreateZone(vm_page_size, vm_page_size, YES);
  50.  
  51.     NXSetRect(&windowRect, 475, 300, 500, 450);
  52.  
  53.     [NXApp getScreens:&screens count:&screenCount];
  54.  
  55.     [commonImageInspector getFrame: &inspectorFrame];
  56.     currentInspector = commonImageInspector;
  57.     
  58.     [self getViewType];
  59.     [self setVirtualViewIndexAndIncrement:NO];
  60.     [self getWindowType];
  61.  
  62.     [self getScreenSaverSetting];
  63.     [self getScreenLockerSetting];
  64.     [self getPrioritySetting];
  65.     [self getImageFile];
  66.     [self getHotCornerSetting];
  67.  
  68.     autoLaunch = NXGetDefaultValue([NXApp appName], "NXAutoLaunch");
  69.     if (strcmp(autoLaunch,"YES"))
  70.     {
  71.         [[windMatrix window] makeKeyAndOrderFront:self];
  72.         windowHasBeenDisplayed = YES;
  73.     }
  74.     else [NXApp hide:self];
  75.     
  76. #ifdef SHOWITERATIONSPERSEC
  77.     then = currentTimeInMs();
  78.     targetTime = then + 10000;
  79. #endif
  80.     
  81.     srandom(time(0));
  82.  
  83.     return self;
  84. }
  85.  
  86. - appDidHide:sender
  87. {
  88.     if (windowType != BACKWINDOW) [self removeTimer];
  89.     return self;
  90. }
  91.  
  92. - appDidUnhide:sender
  93. {
  94.     if (!windowHasBeenDisplayed)
  95.     {
  96.         [[windMatrix window] makeKeyAndOrderFront:self];
  97.         windowHasBeenDisplayed = YES;
  98.     }
  99.  
  100.     if (windowType != NOWINDOW) [self createTimer];
  101.     return self;
  102. }
  103.  
  104.  
  105.  
  106. // Pretty much a dummy function to invoke the step method.
  107.  
  108. void timedEntryFunction (DPSTimedEntry timedEntry, double timeNow, void *theObject)
  109. {    [(id)theObject doDistributorLoop];
  110. }
  111.  
  112. - createTimer
  113. {
  114.     if (!timerValid)
  115.     {
  116.         timerValid = YES;
  117.         timer = DPSAddTimedEntry(0.02, &timedEntryFunction, self, NX_BASETHRESHOLD);
  118.     }
  119.     return self;
  120. }
  121.  
  122. - removeTimer
  123. {
  124.     if (timerValid) DPSRemoveTimedEntry (timer);
  125.     timerValid = NO;
  126.     return self;
  127. }
  128.  
  129. - doDistributorLoop
  130. {
  131.     NXEvent dummyEvent;
  132.     
  133.     keepLooping = YES;
  134.     [spaceView lockFocus];
  135.     if ([spaceView respondsTo:@selector(didLockFocus)]) [spaceView didLockFocus];
  136.  
  137.     do {
  138.         [spaceView oneStep];
  139.         [spaceWindow flushWindow];
  140.         NXPing ();    // Synchronize postscript for smoother animation
  141.  
  142.         [spaceView oneStep];
  143.         [spaceWindow flushWindow];
  144.         NXPing ();    // Synchronize postscript for smoother animation
  145.  
  146. #ifdef SHOWITERATIONSPERSEC
  147.             iterations++;
  148.             if ((now = currentTimeInMs()) > targetTime)
  149.             {
  150.                 printf("BackSpace: %5.1f its/sec\n",
  151.                     (double)iterations*1000.0/(double)(now - then));
  152.                 iterations = 0;
  153.                 targetTime = now + 10000;
  154.                 then = now;
  155.             }
  156. #endif
  157.             
  158.        } while (timerValid && keepLooping &&
  159.             ([NXApp peekNextEvent:NX_ALLEVENTS into:&dummyEvent 
  160.                 waitFor:0 threshold:NX_BASETHRESHOLD] == NULL));
  161.  
  162.     [spaceView unlockFocus];
  163.     
  164.     return self;
  165.  
  166. }
  167.  
  168. - installSpaceViewIntoWindow:w
  169. {
  170.     NXRect cvrect;
  171.     int i;
  172.     id subviews, contentView;
  173.     
  174.     if (!w) return nil;
  175.     contentView = [w contentView];
  176.  
  177.     // get size of content view
  178.     [contentView getBounds:&cvrect];
  179.     
  180.     // remove old subviews, this is overkill really...
  181.     subviews = [contentView subviews];
  182.     for (i=([subviews count]-1); i>=0; i--)
  183.     {    [[subviews objectAt:i] removeFromSuperview];
  184.     }
  185.     
  186.     // install it into the window's content view
  187.     [contentView addSubview:spaceView];
  188.     [contentView setAutoresizeSubviews:YES];
  189.     [spaceView setAutosizing:NX_WIDTHSIZABLE | NX_HEIGHTSIZABLE];
  190.  
  191.     // size the spaceview
  192.     [spaceView sizeTo:cvrect.size.width :cvrect.size.height];
  193.     
  194.     return self;
  195. }
  196.  
  197. - useNormalWindow
  198. {
  199.     int myBacking;
  200.     
  201.     spaceView = [self backView];
  202.     myBacking = [self backingTypeForView:spaceView];
  203.  
  204.     if (!normalWindow)
  205.     {
  206.         normalWindow = [[Window allocFromZone:backZone]
  207.             initContent:&windowRect style:NX_RESIZEBARSTYLE
  208.             backing:myBacking 
  209.             buttonMask:NX_CLOSEBUTTONMASK
  210.             defer:NO];
  211.         
  212.         [self setWindowTitle];
  213.         [normalWindow useOptimizedDrawing:YES];
  214.         [normalWindow setDynamicDepthLimit:YES]; //want window depth to match device!
  215.         [normalWindow setOneShot:YES];
  216.         [normalWindow setDelegate:self];
  217.         [normalWindow setBackgroundGray:NX_BLACK];
  218.     }
  219.  
  220.     spaceWindow = normalWindow;
  221.     [self installSpaceViewIntoWindow:spaceWindow];
  222.  
  223.     if ([spaceView respondsTo:@selector(setImage:)])
  224.         [spaceView setImage: image];
  225.     if ([spaceView respondsTo:@selector(newWindow)]) [spaceView newWindow];
  226.     [spaceWindow display];
  227.  
  228.     [spaceWindow makeKeyAndOrderFront:self];
  229.     
  230.     // need to do this so flushing always works!
  231.     // must do it late because kit does lazy window creation ie the PostScript
  232.     // window might not exist until you actually draw to it
  233.     
  234.     if (myBacking == NX_RETAINED)
  235.         [spaceWindow setBackingType:NX_RETAINED];
  236.     else [spaceWindow setBackingType:NX_BUFFERED];
  237.  
  238.     return self;
  239. }
  240.  
  241. - (int) backingTypeForView:aView
  242. {
  243.     if ([aView respondsTo:@selector(useBufferedWindow)] 
  244.         && [aView useBufferedWindow])
  245.         return NX_BUFFERED;
  246.     return NX_RETAINED;
  247. }
  248.  
  249. - useBackWindow:(int)tier
  250. {
  251.     NXRect r={{0, 0}};
  252.     int myBacking;
  253.     
  254.     [NXApp getScreenSize:&(r.size)];
  255.  
  256.     spaceView = [self backView];
  257.     myBacking = [self backingTypeForView:spaceView];
  258.     
  259.     [self createBigWindowIfNecessaryForView:spaceView];
  260.  
  261.     if (myBacking == NX_RETAINED)
  262.     {    spaceWindow = bigUnbufferedWindow;
  263.         tweakWindow([spaceWindow windowNum], tier);
  264.     }
  265.     else
  266.     {    spaceWindow = bigBufferedWindow;
  267.     }
  268.  
  269.     [self installSpaceViewIntoWindow:spaceWindow];
  270.  
  271.     if ([spaceView respondsTo:@selector(setImage:)])
  272.         [spaceView setImage: image];
  273.  
  274.     [spaceWindow placeWindow:&r];
  275.     if (myBacking == NX_BUFFERED) [spaceWindow display];
  276.  
  277.     [spaceWindow orderFront:self];
  278.     if (myBacking == NX_BUFFERED) tweakWindow([spaceWindow windowNum], tier);
  279.     else [spaceWindow display];
  280.  
  281.     if ([spaceView respondsTo:@selector(newWindow)]) [spaceView newWindow];
  282.  
  283.     return self;
  284. }
  285.  
  286. - createBigWindowIfNecessaryForView:aView
  287. {
  288.     NXRect r={{0, 0}};
  289.     int myBacking = [self backingTypeForView:aView];
  290.     
  291.     [NXApp getScreenSize:&(r.size)];
  292.  
  293.     if ((myBacking == NX_RETAINED) && !bigUnbufferedWindow)
  294.     {
  295.     
  296.         bigUnbufferedWindow = [[BackWindow allocFromZone:backZone]
  297.             initContent:&r style:NX_TOKENSTYLE
  298.             backing:NX_NONRETAINED buttonMask:0 defer:NO];
  299.  
  300.         [bigUnbufferedWindow useOptimizedDrawing:YES];
  301.  
  302.         [bigUnbufferedWindow removeFromEventMask:(NX_LMOUSEDOWNMASK | NX_LMOUSEUPMASK
  303.                  | NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK
  304.                | NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK
  305.                | NX_KEYDOWNMASK | NX_KEYUPMASK
  306.                | NX_CURSORUPDATEMASK)];
  307.         [bigUnbufferedWindow setBackgroundGray:NX_BLACK];
  308.     }
  309.  
  310.     if ((myBacking == NX_BUFFERED) && !bigBufferedWindow)
  311.     {
  312.  
  313.         bigBufferedWindow = [[BackWindow allocFromZone:backZone]
  314.             initContent:&r style:NX_TOKENSTYLE
  315.             backing:NX_BUFFERED buttonMask:0 defer:NO];
  316.  
  317.         [bigBufferedWindow useOptimizedDrawing:YES];
  318.  
  319.         [bigBufferedWindow removeFromEventMask:(NX_LMOUSEDOWNMASK | NX_LMOUSEUPMASK
  320.                  | NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK
  321.                | NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK
  322.                | NX_KEYDOWNMASK | NX_KEYUPMASK
  323.                | NX_CURSORUPDATEMASK)];
  324.  
  325.         [bigBufferedWindow setDynamicDepthLimit:YES]; //want window depth to match device!
  326.         [bigBufferedWindow setOneShot:YES];
  327.         [bigBufferedWindow setBackgroundGray:NX_BLACK];
  328.     }
  329.  
  330.     return self;
  331. }
  332.  
  333. - changeWindowType:sender
  334. {
  335.     [self changeWindowTypeAndRemember:YES];
  336.     return self;
  337. }
  338.  
  339. - changeWindowTypeAndRemember:(BOOL)rem
  340. {
  341.     char str[10];
  342.     int newWindowType;
  343.  
  344.     newWindowType = [windMatrix selectedRow];
  345.     if (newWindowType == windowType) return self;
  346.     
  347.     windowType = newWindowType;
  348.  
  349.     if (rem)
  350.     {
  351.         sprintf(str,"%1d", windowType);
  352.         NXWriteDefault([NXApp appName], "windowType", str);
  353.     }
  354.  
  355.     [spaceWindow orderOut:self];
  356.     
  357.     switch (windowType)
  358.     {
  359.         case NOWINDOW:
  360.             [self removeTimer];
  361.             break;
  362.         case NORMALWINDOW:
  363.             [self useNormalWindow];
  364.             [self createTimer];
  365.             break;
  366.         case BACKWINDOW:
  367.             [self useBackWindow: globalTier];
  368.             [self createTimer];
  369.             break;
  370.     }
  371.     
  372.     return self;
  373. }
  374.  
  375. - getWindowType
  376. {
  377.     int tWindowType = NORMALWINDOW;
  378.     const char *ptr;
  379.     int val;
  380.  
  381.     ptr = NXGetDefaultValue([NXApp appName], "windowType");
  382.     if (ptr)
  383.     {
  384.         sscanf(ptr,"%d",&val);
  385.         if (val >= 0 && val <= 2) tWindowType = val;
  386.     }
  387.     
  388.     [windMatrix selectCellAt:tWindowType :0];
  389.     [self changeWindowTypeAndRemember:NO];
  390.  
  391.     return self;
  392. }
  393.  
  394. - getScreenSaverSetting
  395. {
  396.     const char *ptr;
  397.     
  398.     if((evs = NXOpenEventStatus()) == 0)
  399.     {    perror("NXOpenEventStatus failed.");
  400.         exit(10);
  401.     }
  402.     
  403.     [self getDimBrightness:&dimBrightness];
  404.     
  405.     //in case the old dim brightness is somehow invalid, I reset it
  406.     if (dimBrightness > .25)
  407.     {
  408.         dimBrightness = .25;
  409.         [self _setDimBrightness:&dimBrightness];
  410.     }
  411.  
  412.     [screenSaver setState:0];
  413.     
  414.     ptr = NXGetDefaultValue([NXApp appName], "screenSaver");
  415.  
  416.     if (!ptr || !strcmp(ptr,"Off")) [self setScreenSaver:NO andRemember:NO];
  417.     else [self setScreenSaver:YES andRemember:NO];
  418.     
  419.     return self;
  420. }
  421.  
  422. - changeScreenSaverSetting:sender
  423. {
  424.     [self setScreenSaver:([screenSaver state])andRemember:YES];
  425.     return self;
  426. }
  427.  
  428. - setScreenSaver:(BOOL)val andRemember:(BOOL)rem
  429. {
  430.     [screenSaver setState:val];
  431.     screenSaverVal = val;
  432.     
  433.     if (val)
  434.     {
  435.         // turn it on...
  436.         [self calcDimTime];
  437.         if (rem) NXWriteDefault([NXApp appName], "screenSaver", "On");
  438.     }
  439.     else
  440.     {
  441.         // turn it off...
  442.         if (rem) NXRemoveDefault([NXApp appName], "screenSaver");
  443.     }
  444.     
  445.     return self;
  446. }
  447.  
  448. - calcDimTime
  449. {
  450.     double dimTime;
  451.     [self getDimTime :&dimTime];
  452.     
  453.     if (dimTime < 0) dimTime = .1;
  454.     
  455.     if (screenSaverVal && !doingSaver)
  456.     {
  457.         // printf("BackSpace calcDimTime: dims in %f seconds\n",dimTime);
  458.     
  459.         [self perform:@selector(maybeDoScreenSaver:)
  460.             with:self
  461.             afterDelay:SEC2MS(dimTime)
  462.             cancelPrevious:YES];
  463.     }
  464.             
  465.     return self;
  466. }
  467.  
  468. - maybeDoScreenSaver:sender
  469. {
  470.     NXEvent anEvent;
  471.     BOOL autoDimmed;
  472.  
  473.     // in case timed entry fires but user has killed screen saver
  474.     if (!screenSaverVal || doingSaver) return self;
  475.     
  476.     autoDimmed = NXAutoDimState(evs);
  477.     if (!autoDimmed)
  478.     {
  479.         [self calcDimTime];
  480.         return self;
  481.     }
  482.  
  483.     // The perform:afterDelay: method starts a timed entry to
  484.     // invoke maybeDoScreenSaver, so we are in a timed entry
  485.     // right now.  If we just jumped into doScreenSaver:, we
  486.     // would interrupt the doDistributorLoop method while
  487.     // it's still focused on the spaceView.  By posting an
  488.     // event, we force that loop to bail out so we can jump
  489.     // into the screen saver cleanly.
  490.     
  491.     keepLooping = NO;    // There was a bug related to this at one point.
  492.                         // I don't think it's necessary anymore.
  493.     anEvent.type = NX_APPDEFINED;
  494.     anEvent.data.compound.subtype = BSDOSAVER;
  495.     anEvent.ctxt = [NXApp context];
  496.     DPSPostEvent(&anEvent,0);
  497.     
  498.     return self;
  499. }
  500.  
  501. - applicationDefined:(NXEvent *)theEvent
  502. {
  503.     switch (theEvent->data.compound.subtype)
  504.     {
  505.     case BSDOSAVER:
  506.         [self doScreenSaver:self];
  507.         [self calcDimTime];            // reset to fire again
  508.         break;
  509.     case BSOPENFILE:
  510.         [self doDelayedOpenFile];
  511.         break;
  512.     default:
  513.         break;
  514.     }
  515.     return self;
  516. }
  517.  
  518. - showFakeScreenSaverAfterPause:sender
  519. {
  520.     usleep(250000);
  521.     return [self showFakeScreenSaver:sender];
  522. }
  523.  
  524. - showFakeScreenSaver:sender
  525. {
  526.     [self screenSaverMode];
  527.     NXSetAutoDimState(evs, YES);
  528.     [self doScreenSaver:self];
  529.     NXSetAutoDimState(evs, NO);
  530.     [self normalMode];            //usually not necessary
  531.     
  532.     // reset to fire again
  533.     [self calcDimTime];
  534.         
  535.     return self;
  536. }
  537.  
  538.  
  539. - doScreenSaver:sender
  540. {
  541.     BOOL autoDimmed;
  542.     int oldWindowType;
  543.     BOOL mouseOK, oldTimerValid;
  544.     BOOL ignoreMouseMovement = NO;
  545.     BOOL isHidden;
  546.     NXRect trackingRect;
  547.     NXPoint mouseLoc;
  548.     BOOL passwordOK;
  549.     BOOL stoleActivation = NO;
  550.     int oldActiveApp = 0;
  551.     int iterationCount = 0;
  552.         
  553.     // must be sure we don't enter on timed entry after faking saver
  554.     doingSaver = YES;
  555.     
  556.     isHidden = [NXApp isHidden];
  557.     if (isHidden)
  558.     {
  559.         [NXApp unhideWithoutActivation:self];
  560.     }
  561.  
  562.     // force activation here so we get keystrokes if someone
  563.     // just types his password.
  564.     if ([password isLocked])
  565.     {
  566.         oldActiveApp = [NXApp activateSelf:YES];
  567.         stoleActivation = YES;
  568.     }
  569.     
  570.     [self setVirtualViewIndexAndIncrement:YES];
  571.  
  572.     //save old window state
  573.     oldWindowType = [windMatrix selectedRow];
  574.  
  575.     globalTier = SAVERTIER;
  576.  
  577.     [self blackOutAllScreens];
  578.     
  579.     //background window on screen
  580.     [windMatrix selectCellAt:BACKWINDOW :0];
  581.     [self changeWindowTypeAndRemember:NO];
  582.     
  583.     //nuke timer so timed entry doesn't fire
  584.     oldTimerValid = timerValid;
  585.     [self removeTimer];
  586.  
  587.  
  588.     //set background window tier to SAVERTIER
  589.     if ([self backingTypeForView:spaceView] == NX_BUFFERED)
  590.     {
  591.         // make sure the one shot buffer really exists
  592.         //[spaceWindow display];    //xxx
  593.         if ([spaceWindow windowNum] <= 0) [spaceWindow display];
  594.         PSsetwindowlevel(SAVERTIER, [spaceWindow windowNum]);
  595.     }
  596.     else 
  597.     {
  598.         PSsetwindowlevel(SAVERTIER, [spaceWindow windowNum]);
  599.         [spaceView fillBoundsWithBlack];
  600.         [spaceView display];
  601.     }
  602.  
  603.     NXPing();
  604.     [self screenSaverMode];
  605.  
  606.     PSsetwaitcursorenabled(NO);
  607.  
  608.     if ([spaceView respondsTo:@selector(enteredScreenSaverMode)])
  609.         [spaceView enteredScreenSaverMode];
  610.  
  611.     do {
  612.         //obscure cursor
  613.         PSobscurecursor();
  614.     
  615.         [spaceView lockFocus];
  616.         if ([spaceView respondsTo:@selector(didLockFocus)])
  617.             [spaceView didLockFocus];
  618.  
  619.  
  620.         if ([spaceView respondsTo:@selector(ignoreMouseMovement)])
  621.             ignoreMouseMovement = [spaceView ignoreMouseMovement];
  622.  
  623.         [spaceWindow getMouseLocation:&mouseLoc];
  624.         trackingRect.origin.x = mouseLoc.x - 100;
  625.         trackingRect.origin.y = mouseLoc.y - 100;
  626.         trackingRect.size.width = trackingRect.size.height = 200;
  627.     
  628.         do {
  629.             if ((++iterationCount & 0x7f)==0) PSobscurecursor();
  630.  
  631.             [spaceView oneStep];
  632.             [spaceWindow flushWindow];
  633.             NXPing();    // Synchronize postscript for smoother animation
  634.  
  635.             // note: window and view coordinates the same!
  636.             // so I don't have to convert to view coord system
  637.             if (ignoreMouseMovement) mouseOK = YES;
  638.             else
  639.             {
  640.                 [spaceWindow getMouseLocation:&mouseLoc];
  641.                 mouseOK = [spaceView mouse:&mouseLoc inRect:&trackingRect];
  642.             }
  643.         
  644.             [spaceView oneStep];
  645.             [spaceWindow flushWindow];
  646.             NXPing();    // Synchronize postscript for smoother animation
  647.  
  648.             autoDimmed = NXAutoDimState(evs);
  649.         } while (autoDimmed && mouseOK);
  650.     
  651.         [spaceView unlockFocus];
  652.  
  653.         // force activation here in case anyone changed it out
  654.         // from under me.  (workspace does this, dog gone it!)
  655.         if ([password isLocked])
  656.         {
  657.             [NXApp activateSelf:YES];
  658.         }
  659.  
  660.         passwordOK = [password checkPassword: 
  661.             NXLocalString("Screen is locked.  Enter password to unlock:",0,0) 
  662.             randomPos:YES checkLock:YES withView:spaceView];
  663.  
  664.         if (!passwordOK) NXSetAutoDimState(evs, YES);
  665.  
  666.     } while (!passwordOK);
  667.  
  668.     if ([spaceView respondsTo:@selector(willExitScreenSaverMode)])
  669.         [spaceView willExitScreenSaverMode];
  670.  
  671.     NXSetAutoDimState(evs, NO);
  672.  
  673.     PSsetwaitcursorenabled(YES);
  674.  
  675.     [self normalMode];
  676.  
  677.     //background window tier to BACKGROUNDTIER
  678.     PSsetwindowlevel(BACKGROUNDTIER, [spaceWindow windowNum]);
  679.     globalTier = BACKGROUNDTIER;
  680.     
  681.     if (([self backingTypeForView:spaceView] != NX_BUFFERED) &&
  682.             oldWindowType == BACKWINDOW)
  683.         // this justs fixes a display bug for really lazy nonretained windows
  684.     {
  685.         [spaceView fillBoundsWithBlack];
  686.         [spaceView display];
  687.     }
  688.  
  689.     if (oldTimerValid)    [self createTimer];
  690.  
  691.     [self unBlackOutAllScreens];
  692.     
  693.     //restore old window state
  694.     [windMatrix selectCellAt:oldWindowType :0];
  695.     [self changeWindowTypeAndRemember:NO];
  696.  
  697.     if (stoleActivation) 
  698.     {
  699.         if (oldActiveApp) [NXApp activate:oldActiveApp];
  700.         else [NXApp deactivateSelf];
  701.     }
  702.  
  703.     if (isHidden)
  704.     {
  705.         [NXApp hide:self];
  706.     }
  707.  
  708.     doingSaver = NO;
  709.  
  710.     return self;
  711. }
  712.  
  713. - appWillTerminate:sender
  714. {
  715.     [self normalMode];
  716.     return self;
  717. }
  718.  
  719. - appDidBecomeActive:sender
  720. {
  721.     id theMatrix;
  722.  
  723.     theMatrix = [viewSelectionBrowser matrixInColumn:0];
  724.     [theMatrix scrollCellToVisible:realViewIndex :0];
  725.     return self;
  726. }
  727.  
  728. - app:sender powerOffIn:(int)ms andSave:(int)aFlag
  729. {
  730.     return [NXApp terminate:self];
  731. }
  732.  
  733. - getPrioritySetting
  734. {
  735.     const char *ptr;
  736.     int val;
  737.  
  738.     [mySlider setMinValue: 0];
  739.     [mySlider setMaxValue: 10];
  740.     
  741.     ptr = NXGetDefaultValue([NXApp appName], "priority");
  742.     if (ptr)
  743.     {
  744.         sscanf(ptr,"%d",&val);
  745.         if (val >= 0 && val <= 10) priority = val;
  746.         else priority = 4;
  747.     }
  748.     else priority = 4;
  749.     
  750.     [[mySlider cell] setIntValue:priority];
  751.     [[priorityLevel cell] setIntValue:priority];
  752.  
  753. //    use mach call rather than unix - mach lets me increase priority!
  754. //    setpriority(PRIO_PROCESS, 0, priority);
  755.     cthread_priority(cthread_self(), priority, FALSE);
  756.  
  757.     return self;
  758. }
  759.  
  760. - changeSliderValue:sender
  761. {
  762.     priority = [[mySlider cell] intValue];
  763.     [[priorityLevel cell] setIntValue:priority];
  764.     return self;
  765. }
  766.  
  767. - saveSliderValue
  768. {
  769.     char str[50];
  770. //    setpriority(PRIO_PROCESS, 0, priority);
  771.     cthread_priority(cthread_self(), priority, FALSE);
  772.  
  773.     sprintf(str,"%d", priority);
  774.     NXWriteDefault([NXApp appName], "priority", str);
  775.     return self;
  776. }
  777.  
  778. - windowWillResize:sender toSize:(NXSize *)frameSize
  779. {
  780.     if (frameSize->width < 100) frameSize->width = 100;
  781.     if (frameSize->height < 100) frameSize->height = 100;
  782.     return self;
  783. }
  784.  
  785. - windowWillClose:sender
  786. {
  787.     [windMatrix selectCellAt:NOWINDOW :0];
  788.     [self perform:@selector(changeWindowType:) with:self
  789.         afterDelay:1 cancelPrevious:YES];
  790.     return nil;
  791. }
  792.  
  793. BStimeval currentTimeInMs()
  794. {
  795.     struct timeval curTime;
  796.     gettimeofday (&curTime, NULL);
  797.     return (curTime.tv_sec) * 1000 + curTime.tv_usec / 1000;
  798. }
  799.  
  800. //
  801. //  Additional methods to handle a common image object for views.
  802. //  Lennart Lovstrad, Rank Xerox EuroPARC, August 1991.
  803. //
  804.  
  805. - setImageFromFile: (const char *) filename
  806. {
  807.     [image free];
  808.  
  809.     image = [[NXImage alloc] initFromFile: filename];
  810.     if (image == nil)
  811.     {
  812.         NXRunAlertPanel([NXApp appName], NXLocalString("Could not open %s",0,0),
  813.                 NULL, NULL, NULL, filename);
  814.         image = nil;
  815.         //return nil;    //can't return, image is invalid
  816.     }
  817.     
  818.     return [self commonImageInit];
  819. }
  820.  
  821. - setImageFromName: (const char *) name
  822. {
  823.     [image free];
  824.     image = [[NXImage alloc] initFromSection: name];
  825.     
  826.     return [self commonImageInit];
  827. }
  828.  
  829. - commonImageInit
  830. {
  831.     [imageView setImage: image];
  832.     [imageView display];
  833.  
  834.     if ([spaceView respondsTo:@selector(setImage:)])
  835.         [spaceView setImage: image];
  836.  
  837.     if ([self backingTypeForView:spaceView] != NX_BUFFERED)
  838.     {
  839.         [spaceView fillBoundsWithBlack];
  840.         [spaceView display];
  841.     }
  842.  
  843.     return self;
  844. }
  845.  
  846. - getImageFile
  847. {
  848.     const char *filename;
  849.  
  850.     filename = NXGetDefaultValue([NXApp appName], "imageFile");
  851.     if (filename)
  852.         [self setImageFromFile: filename];
  853.     else [self setImageFromName: "defaultImage"];
  854.  
  855.     return self;
  856. }
  857.  
  858. - setImageFileFrom: sender
  859. {
  860.     id openPanel = [OpenPanel new];
  861.     const char *fileTypes[] = {"tiff", "eps", NULL};
  862.     
  863.     if ([openPanel runModalForTypes: fileTypes])
  864.     {
  865.         [self setImageFromFile: [openPanel filename]];
  866.         NXWriteDefault([NXApp appName], "imageFile", [openPanel filename]);
  867.     }
  868.  
  869.     [spaceView display];    //don't know why this is necessary...
  870.  
  871.     return self;
  872. }
  873.  
  874. // This should return a float between 0 and 1
  875. float frandom()
  876. {
  877.     float val = (random() & 0x7fffffff);
  878.     val /= 0x7fffffff;
  879.     return val;
  880. }
  881.  
  882. float randBetween(float a, float b)
  883. {
  884.     float val, scale, t;
  885.  
  886.     if (a > b)
  887.     {    t = a; a = b; b = t;
  888.     }
  889.     
  890.     scale = (b-a);
  891.     val = scale * frandom();
  892.     return (a + val);
  893. }
  894.  
  895. @end
  896.